#!/net/public/tal/dialogue/bin/idial

-- initiation des paths
function paths_init()
      paths.regles  = "regles:listes"
      paths.db      = "bd"
end

-- Misc functions : parcours des arbres et 
-- extraction des valeurs et des attributs

function node_to_word(n)
   local s = tostring(n:value())
   if(s == nil) then
      s = ""
   end
   return s
end

-- Parcours des arbres

function tree_to_xtag(t)
   local i,n,r
   r = ""
   for i,n in ipairs(t:children()) do
      if(i ~= 1) then
         r = r.." "
      end

      if(n:child_count() ~= 0) then
         r = r.."<"..node_to_word(n).."> "..tree_to_xtag(n).." </"..node_to_word(n)..">"
      else
         r = r..node_to_word(n)
      end
   end
   return r
end

function tree_has_tag(tree,tag)
   local i,n
   for i,n in ipairs (tree:children()) do
      if (n:value()==tag) then
	 return true
      end
      if (n:child_count() ~= 0) then
         if (tree_has_tag(n,tag)) then
	    return true
         end
      end
   end
   return false
end

function liste_has_value(list,value)
   local i,n
   for i,n in ipairs (list) do
      if (n==value) then
	 return true
      end
   end
   return false
end

function tree_has_list(tree,list)
   local i,n
   for i,n in ipairs (tree:children()) do
      if (liste_has_value(list,n:value())) then
	 return true
      end
      if (n:child_count() ~= 0) then
         if (tree_has_list(n,list)) then
	    return true
         end
      end
   end
   return false
end

function extract_tag_1(tree,tag,r)
   local i,n
   for i,n in ipairs (tree:children()) do
      if (n:child_count()~=0) then
         if (n:value()==tag) then
            extract_value(n,r)
         else
            extract_tag_1(n,tag,r)
         end
      end
   end
end

function extract_value(n,r)
   local res = ""
   local i,v 
   for i,v in ipairs (n:children()) do
      if (i~=1) then
	 res = res.." "
      end
      res=res..v:value()
   end
   table.insert(r,res)
end

function table_has_field(t,a)
   local i,v
   for i,v in ipairs (a) do
      if t[v] then
	 return true
      end
   end
   return false
end

function table_copy_fields(tn,to,a)
   local i,v
   for i,v in ipairs (a) do
      if (to[v]) then
	 tn[v]=to[v]
      end
   end
end


function extract_tag(tree,tag)
   local r = {}
   extract_tag_1(tree,tag,r)
   return r
end

function extract_tag_multi(tree,list)
   local i,n 
   local res = {}
   for i,n in ipairs(list) do
      local r = extract_tag(tree,n)
      if (table.getn(r)~=0) then
	 res[n]=r
      end
   end
   return res
end


-- Non contextual analysis 
-- declaration du ou des fichiers de regles wmatch

function nca_init()
   wmatch.set_path(paths.regles)
   wm1 = wmatch.load("cardorinaux.wm")
   wm2 = wmatch.load("date.wm")
   wm3 = wmatch.load("topic.wm")
   wm4 = wmatch.load("foot_regles.wm")
   wm5 = wmatch.load("final.wm")
   wm6 = wmatch.load("dialogue.wm")
end

-- appel du ou des fichiers de regles avec les parametres
-- nooverlap_global_tree = -S
function nca_run(sentence)
   local r
   r = wm1:match_left_recurse(sentence)
   r = wmatch.numbers(r)
   r = wm2:match_nooverlap_global_tree(r)
   r = wm3:match_nooverlap_global_tree(r)
   r = wm4:match_nooverlap_global_tree(r)
   r = wm5:match_nooverlap_global_tree(r)
   r = wm6:match_nooverlap_global_tree(r)
   return r;
end

-- Dialogue
function guide(utterance)
   local rep=extract_tag(utterance,"_rep")
   local rep_count=table.getn(rep)
   local y_question=tree_has_list(utterance,liste_tag_complete)
   if (y_question) then
      return
   end
   if (rep_count==0) then 
      return {acte="guide"}
   end
   if (liste_has_value({"_Doui","_Dguide"},rep[1])) then 
      return {acte="guide"}
   end
end

-- dialogue pour la recherche dans la base de données
function dial_db(utterance)

-- déclation des variables locales
   local info=extract_tag_multi(utterance,liste_tag_rechdb)
   local liste_T = {"_Tscore", "_Tequipe", "_Tbuteur", "_Tvainqueur", "_Tqdate", "_Tdate", "_Tgagner"}

   local y_T = table_has_field(info,liste_T)

-- création de l'historique
   hist_rechdb:store("info_hc", info)

   local info_prec=hist_rechdb:get(-1).info_ec

   -- Application au type T_Equipe :
   
   if (info_prec) then
      local y_T_prec = table_has_field(info_prec,liste_T)
      if (info._Tequipe) and (not y_T) and (y_T_prec) then
	 table_copy_fields (info,info_prec,liste_T)
      elseif (not info._Tequipe) and (y_T) and (info_prec._Tequipe) then
	 info._Tequipe=info_prec._Tequipe
      end
   end
	 
   hist_rechdb:store("info_ec", info)

   -- Score entre deux equipes
   if ((info._Tscore) and (not info._Tequipe)) then
      return {acte="reponse";content="pasdescore"}
   end
   if ( (info._Tscore) and (info._Tequipe[1]) and (info._Tequipe[2])) then
      local rechScore=caps:select{equipe1=info._Tequipe[1];equipe2=info._Tequipe[2]}
      if (rechScore:line_count()<1) then
	 return {acte="reponse";content="score_inconnu";equipe1=info._Tequipe[1];equipe2=info._Tequipe[2]}
      end
      return {acte="reponse";content="score";equipe1=info._Tequipe[1];equipe2=info._Tequipe[2];score=rechScore:line(1).score}
   end
   
   
   -- Vainqueur entre deux equipes
 if ((info._Tvainqueur) and (not info._Tequipe)) then
      return {acte="reponse";content="pasdevainqueur"}
   end   
  if ( (info._Tvainqueur) and (info._Tequipe[1]) and (info._Tequipe[2])) then
      local rechVainqueur=caps:select{equipe1=info._Tequipe[1];equipe2=info._Tequipe[2]}
      if (rechVainqueur:line_count()<1) then
	 return {acte="reponse";content="vainqueur_inconnu";equipe1=info._Tequipe[1];equipe2=info._Tequipe[2]}
      end
      return {acte="reponse";content="vainqueur";equipe1=info._Tequipe[1];equipe2=info._Tequipe[2];vainqueur=rechVainqueur:line(1).vainqueur}
   end
   
   
  -- Date d'un match entre deux equipes
   if ((info._Tqdate) and (not info._Tequipe)) then
      return {acte="reponse";content="pasdedate"}
   end  
  if ( (info._Tqdate) and (info._Tequipe[1]) and (info._Tequipe[2])) then
      local rechDate=caps:select{equipe1=info._Tequipe[1];equipe2=info._Tequipe[2]}
      if (rechDate:line_count()<1) then
	 return {acte="reponse";content="date_inconnue";equipe1=info._Tequipe[1];equipe2=info._Tequipe[2]}
      end
      return {acte="reponse";content="date";equipe1=info._Tequipe[1];equipe2=info._Tequipe[2];date=rechDate:line(1).date}
   end
  

  -- Date ou une equipe a gagne un match
  if ((info._Tqdate) and (not info._Tequipe)) then
      return {acte="reponse";content="pasdedate2"}
   end  
  if ( (info._Tqdate) and (info._Tequipe[1]) and info._Tgagner) then
      local rechDate=caps:select{equipe1=info._Tequipe[1];vainqueur=info._Tequipe[1]}
      if (rechDate:line_count()<1) then
	 return {acte="reponse";content="date2_inconnue";equipe1=info._Tequipe[1];vainqueur=info._Tequipe[1]}
      end
      return {acte="reponse";content="date2";equipe1=info._Tequipe[1];vainqueur=info._Tequipe[1];date=rechDate:line(1).date}
   end
   
  
  -- Vainqueur d'un match avec une équipe à une date précise
  if ((info._Tvainqueur) and (not info._Tdate) and (not info._Tequipe) ) then
      return {acte="reponse";content="pasdevainqueur2"}
   end
  if ( (info._Tvainqueur) and (info._Tdate)  and (info._Tequipe)) then
      local rechVainqueur2=caps:select{equipe1=info._Tequipe[1];date=info._Tdate[1]}
      if (rechVainqueur2:line_count()<1) then
	 return {acte="reponse";content="vainqueur2_inconnu";equipe1=info._Tequipe[1];date=info._Tdate[1]}
      end
      return {acte="reponse";content="vainqueur2";equipe1=info._Tequipe[1];date=info._Tdate[1];vainqueur=rechVainqueur2:line(1).vainqueur}
   end
   
   
   -- Score d'un match avec une équipe à une date précise
   if ((info._Tscore) and (not info._Tdate) and (not info._Tequipe) ) then
      return {acte="reponse";content="pasdescore2"}
   end
   if ( (info._Tscore) and (info._Tdate)  and (info._Tequipe)) then
      local rechScore2=caps:select{equipe1=info._Tequipe[1];date=info._Tdate[1]}
      if (rechScore2:line_count()<1) then
	 return {acte="reponse";content="score2_inconnu";equipe1=info._Tequipe[1];date=info._Tdate[1]}
      end
      return {acte="reponse";content="score2";equipe1=info._Tequipe[1];date=info._Tdate[1];score=rechScore2:line(1).score}
   end
   
   
   -- Buteur(s) d'une équipe d'un match à une date précise
   if ((info._Tbuteur) and (not info._Tdate) and (not info._Tequipe) ) then
      return {acte="reponse";content="pasdebuteurs"}
   end
   if ( (info._Tbuteur) and (info._Tdate)  and (info._Tequipe)) then
      local rechButeurs=caps:select{equipe1=info._Tequipe[1];date=info._Tdate[1]}
      if (rechButeurs:line_count()<1) then
	 return {acte="reponse";content="buteurs_inconnus";equipe1=info._Tequipe[1];date=info._Tdate[1]}
      end
      return {acte="reponse";content="buteurs";equipe1=info._Tequipe[1];date=info._Tdate[1];buteurEquipe1=rechButeurs:line(1).buteurEquipe1}
   end
   
   
   --return dial_rel{utterance}
	return {acte="reponse";content="saispas"}
end

function dial(utterance)
   local rep=extract_tag(utterance,"_rep")
   local y_rechdb=tree_has_list(utterance,liste_tag_rechdb)
   if (y_rechdb) then
      return dial_db(utterance)
   elseif (liste_has_value({"_Dfermeture"},rep[1])) then 
      return {acte="fermeture"}
   elseif (liste_has_value({"_Dguide"},rep[1])) then 
      return {acte="guide"}
   end
   return {acte="relance"}
end

-- Generation
function genere_guide()
   return "Par le simple usage de la parole vous pouvez obtenir des informations sur n'importe quel sujet. Pour cela, il vous suffit de poser simplement votre question. Quelle information d�sirez-vous ?"
end

function genere_fermeture()
   return "Merci d'avoir utilisé ce service d'informations du football. Bonne journée!"
end

function genere_relance()
   return "Que désirez-vous ?"
end

function genere_relance_apres_rep()
   return "Avez vous autre chose à demander ?"
end

-- generation apres recherche db
function genere_reponse_db()
   return "Je dois aller chercher dans ma base de données."
end

-- generation/relance recherche db score
function genere_score(frame)
   return frame.score .. " est le score du match entre "..frame.equipe1.." et "..frame.equipe2.."."
end

function genere_pasdescore()
   return "De quel match souhaitez-vous le score ?"
end

function genere_score_inconnu()
   return "Je suis désolée, mais je n'ai pas de ce score dans ma base de données".."."
end

function genere_score2(frame)
   return frame.score .. " est le score du match du "..frame.date.." avec "..frame.equipe1.."."
end

function genere_pasdescore2()
   return "De quel match souhaitez-vous le score ?"
end

function genere_score2_inconnu()
   return "Je suis désolée, mais je n'ai pas de ce score dans ma base de données".."."
end

-- generation/relance recherche db vainqueur
function genere_vainqueur(frame)
   return frame.vainqueur .. " est le vainqueur du match entre "..frame.equipe1.." et "..frame.equipe2.."."
end

function genere_pasdevainqueur()
   return "De quel match souhaitez-vous le vainqueur ?"
end

function genere_vainqueur_inconnu()
   return "Je suis désolée, mais je n'ai pas de ce vainqueur dans ma base de données".."."
end

function genere_vainqueur2(frame)
   return frame.vainqueur.." est le vainqueur du match du "..frame.date.." avec "..frame.equipe1.."."
end

function genere_pasdevainqueur2()
   return "De quel match souhaitez-vous le vainqueur ?"
end

function genere_vainqueur2_inconnu()
   return "Je suis désolée, mais je n'ai pas de ce vainqueur dans ma base de données".."."
end

-- generation/relance recherche db date
function genere_date(frame)
   return frame.date .. " est la date du match entre "..frame.equipe1.." et "..frame.equipe2.."."
end

function genere_pasdedate()
   return "De quel match souhaitez-vous la date ?"
end

function genere_date_inconnue()
   return "Je suis désolée, mais je n'ai pas de cette date dans ma base de données".."."
end

function genere_date2(frame)
   return frame.date .. " est la date où "..frame.equipe1.." a gagné."
end

function genere_pasdedate2()
   return "De quel match souhaitez-vous la date ?"
end

function genere_date2_inconnue()
   return "Je suis désolée, mais je n'ai pas de cette date dans ma base de données".."."
end

-- generation/relance recherche db buteurs
function genere_buteurs(frame)
   return frame.buteurEquipe1.." est le buteur/sont les buteurs du match du "..frame.date.." avec "..frame.equipe1.."."
end

function genere_pasdebuteurs()
   return "De quel match souhaitez-vous les buteurs ?"
end

function genere_buteurs_inconnus()
   return "Je suis désolée, mais je n'ai pas de buteurs de ce match dans ma base de données".."."
end


-- generation:squelette
function genere (frame)
   if (frame.acte=="fermeture") then 
      return genere_fermeture() 
   elseif (frame.acte=="guide") then
      return genere_guide()
   elseif (frame.acte=="relance") then
      return genere_relance()
   
   elseif ((frame.acte=="reponse") and (frame.content=="score")) then
      return genere_score(frame).." "..genere_relance_apres_rep()
   elseif ((frame.acte=="reponse") and (frame.content=="score_inconnu")) then
      return genere_score_inconnu().." "..genere_relance_apres_rep()	  
   elseif ((frame.acte=="reponse") and (frame.content=="pasdescore")) then
      return genere_pasdescore()
   
   elseif ((frame.acte=="reponse") and (frame.content=="vainqueur")) then
      return genere_vainqueur(frame).." "..genere_relance_apres_rep()
   elseif ((frame.acte=="reponse") and (frame.content=="vainqueur_inconnu")) then
      return genere_vainqueur_inconnu(frame).." "..genere_relance_apres_rep()	  
   elseif ((frame.acte=="reponse") and (frame.content=="pasdevainqueur")) then
      return genere_pasdevainqueur(frame)
   
   elseif ((frame.acte=="reponse") and (frame.content=="date")) then
      return genere_date(frame).." "..genere_relance_apres_rep()
   elseif ((frame.acte=="reponse") and (frame.content=="date_inconnue")) then
      return genere_date_inconnue().." "..genere_relance_apres_rep()	  
   elseif ((frame.acte=="reponse") and (frame.content=="pasdedate")) then
      return genere_pasdedate()

   elseif ((frame.acte=="reponse") and (frame.content=="date2")) then
      return genere_date2(frame).." "..genere_relance_apres_rep()
   elseif ((frame.acte=="reponse") and (frame.content=="date2_inconnue")) then
      return genere_date2_inconnue().." "..genere_relance_apres_rep()	  
   elseif ((frame.acte=="reponse") and (frame.content=="pasdedate2")) then
      return genere_pasdedate2()
	  
   elseif ((frame.acte=="reponse") and (frame.content=="vainqueur2")) then
      return genere_vainqueur2(frame).." "..genere_relance_apres_rep()
   elseif ((frame.acte=="reponse") and (frame.content=="vainqueur2_inconnu")) then
      return genere_vainqueur2_inconnu().." "..genere_relance_apres_rep()	  
   elseif ((frame.acte=="reponse") and (frame.content=="pasdevainqueur2")) then
      return genere_pasdevainqueur2()
	  
   elseif ((frame.acte=="reponse") and (frame.content=="score2")) then
      return genere_score2(frame).." "..genere_relance_apres_rep()
   elseif ((frame.acte=="reponse") and (frame.content=="score2_inconnu")) then
      return genere_score2_inconnu().." "..genere_relance_apres_rep()	  
   elseif ((frame.acte=="reponse") and (frame.content=="pasdescore2")) then
      return genere_pasdescore2()  
	  
   elseif ((frame.acte=="reponse") and (frame.content=="buteurs")) then
      return genere_buteurs(frame).." "..genere_relance_apres_rep()
   elseif ((frame.acte=="reponse") and (frame.content=="buteurs_inconnus")) then
      return genere_buteurs_inconnus().." "..genere_relance_apres_rep()	  
   elseif ((frame.acte=="reponse") and (frame.content=="pasdebuteurs")) then
      return genere_pasdebuteurs()  
	  
	  
   --elseif ((frame.acte=="reponse") and (frame.content=="saispas")) then
	  --return genere_saispas(frame)
  
    else   
      local rep="Désolée, je ne connais pas cette réponse."
      local k,v 
      for k,v in pairs(frame) do
	 rep=rep.." "..k.."="..v
      end
      return rep
   end
end

-- Task

-- chargement de la base de données
function task_init()
   caps = db.load_frame(paths.db.."/BDFootball.txt")
end

-- Master program

function nlg_send(line)
   if(comp.interactive()) then
      io.write("nlg: "..line.."\n")
   else
      comp.msg("nlg", nil, line)
   end
end

function master_init()
   nlg_send("Bonjour et bienvenue sur le service d'informations du football. Que désirez-vous ?")
   nca_init()
   first_utterance = true
-- définition des listes de tags utilisées
--A compléter...
-- 
   liste_tag_complete = {"_Tscore", "_Tequipe", "_Tdate", "_Tqdate", "_Tbuteur", "_Tvainqueur", "_rep", "_Tgagner"}
   liste_tag_rechdb = {"_Tscore", "_Tequipe", "_Tqdate", "_Tdate", "_Tbuteur", "_Tvainqueur", "_Tgagner"}
   hist_rechdb = hist.new()
end

function master_got_utterance(utterance)
   local r = nca_run(utterance)
   local gframe
   io.write("NCA result: "..tree_to_xtag(r).."\n")
   if (not gframe) then
      gframe = dial(r)
   end
   if (not gframe) then
      gframe={acte="relance"}
   end

   nlg_send(genere(gframe))

   first_utterance = false
   hist_rechdb:step()
end


-- User interface

if(comp.interactive()) then
   paths_init()
end

task_init()

if(comp.interactive()) then
   master_init()
   comp.readline(master_got_utterance)
else
   comp.listen("control", nil, function (msg)
				  if(msg == "start") then master_init() end
			       end)
   comp.listen("dialogue", nil, function(msg) master_got_utterance(msg.sentence) end)
end
